<template>
    <div>
        <div class="quill-editor">
            <div ref="editor"></div>
        </div>
        <input @change="upload" accept="image/*" ref="imageUploader" style="display:none" type="file"/>
        <input @change="upload" accept="video/*" ref="videoUploader" style="display:none" type="file"/>
    </div>
</template>
<script lang="ts">
  // api
  import UploadApi from '@/api/upload/uploadApi';
  import Quill, {QuillOptionsStatic} from 'quill';
  import {Component, Model, Prop, Vue, Watch} from 'vue-property-decorator';

  interface HTMLInputEvent extends Event {
    target: HTMLInputElement & EventTarget;
  }

  @Component
  export default class Editor extends Vue {
    @Model('changeContent')
    @Prop()
    public content!: string;
    @Prop({
      default: false
    })
    public disabled!: boolean;
    @Prop({
      required: true
    })
    public uploadPath!: string;

    public value!: string;
    public quill!: Quill;
    public editorOption: QuillOptionsStatic = {
      modules: {
        toolbar: [
          ['bold', 'italic', 'underline', 'strike'],
          ['blockquote', 'code-block'],
          [{list: 'ordered'}, {list: 'bullet'}],
          [{script: 'sub'}, {script: 'super'}],
          [{indent: '-1'}, {indent: '+1'}],
          [{direction: 'rtl'}],
          [{header: [1, 2, 3, 4, 5, 6, false]}, {size: []}, {font: []}],
          [{color: []}, {background: []}, {align: []}],
          ['clean'],
          ['link', 'image']
        ]
      },
      placeholder: '请输入内容...',
      readOnly: false,
      theme: 'snow'
    };

    public get editor(): Element {
      return this.$refs.edit as Element;
    }

    public created() {
      this.value = this.content;
    }

    @Watch('content')
    public contentChangeHandler(newVal: string): void {
      if (this.quill) {
        if (newVal && newVal !== this.value) {
          this.value = newVal;
          this.quill.pasteHTML(newVal);
        } else if (!newVal) {
          this.quill.setText('');
        }
      }
    }

    @Watch('disabled')
    public disabledChangeHandler(newVal: boolean): void {
      if (this.quill) {
        this.quill.enable(!newVal);
      }
    }

    public mounted(): void {
      this.initialize();
      if (this.quill) {
        this.quill.getModule('toolbar').addHandler('image', this.imgHandler);
        this.quill.getModule('toolbar').addHandler('video', this.videoHandler);
      }
    }

    public initialize() {
      if (!this.$el) {
        return;
      }

      const element = this.$el.children[0].children[0] as Element;

      // Instance
      this.quill = new Quill(element, this.editorOption);

      this.quill.enable(false);

      // Set editor content
      if (this.content) {
        this.quill.pasteHTML(this.content);
      }

      // Disabled editor
      if (!this.disabled) {
        this.quill.enable(true);
      }

      // Mark model as touched if editor lost focus
      this.quill.on('selection-change', (range) => {
        this.$emit(!range ? 'blur' : 'focus', this.quill);
      });

      // Update model if text changes
      this.quill.on('text-change', () => {
        let html = element.children[0].innerHTML;
        const quill = this.quill;
        const text = this.quill.getText();
        if (html === '<p><br></p>') {
          html = '';
        }
        this.value = html;
        this.$emit('changeContent', this.value);
        this.$emit('change', {html, text, quill});
      });

      // Emit ready event
      this.$emit('ready', this.quill);
    }

    public imgHandler(state: boolean): void {
      if (!state) {
        return;
      }

      (this.$refs.imageUploader as HTMLDivElement).click();
    }

    public videoHandler(state: boolean): void {
      if (!state) {
        return;
      }

      (this.$refs.videoUploader as HTMLDivElement).click();
    }

    public upload(e: HTMLInputEvent): void {
      const files = e.target.files;

      if (files == null) {
        return;
      }

      UploadApi.single(files[0], this.uploadPath).then((res) => {
        const quill = this.quill;
        if (!quill) {
          return;
        }

        const url = this.$getImageUrl(res.webPath);
        const contentType = res.contentType;
        const type = contentType.split('/')[0];
        const addRange = quill.getSelection();
        quill.insertEmbed(
          addRange !== null ? addRange.index : 0,
          type,
          url,
          (Quill as any).sources.USER
        );
      });
    }
  }
</script>
